/** @jsxImportSource @emotion/react */
import { jsx, css, keyframes } from "@emotion/react";
import * as React from "react";
//import {VisuallyHidden} from "@reach/visually-hidden";
import * as VisuallyHidden from '@radix-ui/react-visually-hidden';
import PropTypes from "prop-types";
import { Text } from "./Text";
import { useTheme } from "./Theme/Providers";


const spin = keyframes`
  to { 
    transform: rotate(360deg); 
  }
`;

const sizeStyles = {
    xs: css({ width: "1rem", height: "1rem" }),
    sm: css({ width: "3rem", height: "3rem" }),
    md: css({ width: "5rem", height: "5rem" }),
    lg: css({ width: "8rem", height: "8rem" }),
    xl: css({ width: "12rem", height: "12rem" })
};

interface SpinnerProps extends React.HTMLAttributes<HTMLDivElement> {
    /** The delay (in ms) before the spinner will appear
     * delay这段时间内，也没办法点击页面按钮的,也要同步等待后端的应答返回来，用户才能继续操作。
     *  */
    delay?: number;
    size?: "xs" | "sm" | "md" | "lg" | "xl";
    /** Attempt to center the spinner in the parent element */
    center?: boolean;
    /** Use an optional label */
    label?: string;
    //正在同步执行中,等待后端返回结果
    doing: boolean;
    //是否在左右轮播台右边半边的页面：针对在手机轮播台场景的需要：右半边和左半边分开显示的。
    carousel?: boolean;
}

// spinner css based on one provided by bootstrap
// https://getbootstrap.com/docs/4.3/components/spinners/
/** 替换LayerLoading功能；
 * 同步化处理 Spinner，
 * 执行操作不等待不可行啊，又不是查询，查询允许异步可以一块一块数据块的揭示出来，查询异步并发没伤害。
 *但是命令操作处理就不一样了，在后端应答之前，应当阻止用户操作， 防止业务逻辑混淆或错误。
 * 没有等待超时的机制？ 一直会等待；想要终止：用户主动得强制刷新URL，超过时间期限的操作无法撤销啊。
 * 假如用户强制刷新退出Spinner的，就无法保障后端服务器的操作结果能够正常通知用户了，一无所知了，用户只能主动查询了，新增加数据无法正常通知到位。
 *对比的是，异步模式用这个 <Suspense fallback={'Loading fallback...'}>  </Suspense>不用等待/可以并发的。
 * @param carousel :轮播台形态的手机竖屏模式，若Spinner是出现在右侧半边页面之中的=true。
 * */
export const Spinner =
({
     delay = 400,
     size = "md",
     center=true,
     label,
     doing=false,
     carousel=false,
     ...other
 }:SpinnerProps) => {
    const theme = useTheme();
    const [show, setShow] = React.useState(delay === 0 ? true : false);

    React.useEffect(() => {
        const timer = setTimeout(() => {
            setShow(true);
        }, delay);

        return () => {
            clearTimeout(timer);
        };
    }, [delay]);

    return (
        <div className="Spinner"
             css={{
                 left: 0,
                 bottom: 0,
                 zIndex: theme.zIndices.waituntil,
                 position: "absolute",
                 top: 0,
                 right: 0,
                 borderRadius: theme.radii.lg,
                 display: "flex",
                 alignItems: "center",
                 justifyContent: "center",
                 background:  "rgba(255,255,255,0.7)",
                 transition: "opacity 0.3s ease",
                 pointerEvents: doing ? "auto" : "none",
                 opacity: doing ? 1 : 0,
                 //决定遮盖不能允许点击的范围, 手机两半页面左右轮播台需要匹配200vw遮盖。
                 width: carousel? '200vw' : undefined,
                 [theme.mediaQueries.md]: {
                     left: "-30vw",
                     width: "130vw",
                     top: "-30vh",
                     height: "130vh",
                 },
                 [theme.mediaQueries.lg]: {
                     left: "-50vw",       //圈圈的可点击取消的遮盖层大小和位移 调整：由于Spinner嵌套在Dialog底下产生相对位置偏离问题。
                     width: "150vw",
                     top: "-50vh",
                     height: "150vh",
                 },
                 "@media print": {
                     transition: 'unset',
                 },
             }}
             {...other}
        >
            <div
                className="Spinner__sync"
                css={[
                    {
                        opacity: show ? 1 : 0,
                        display: "inline-block",
                        transition: "opacity 0.4s cubic-bezier(0.35,0,0.25,1)"
                    },
                    center && {
                        left:  carousel? '100vw' : 0,      //遮盖背后按钮防止被点击触发
                        bottom: 0,
                        width: "100%",
                        height: "100%",
                        boxSizing: "border-box",
                        display: "flex",
                        alignItems: "center",
                        alignSelf: "center",
                        justifyContent: "center",
                        position: "fixed"
                    },
                    {
                        "@media print": {
                            transition: 'unset',
                        },
                    }
                ]}
            >
                <div
                    className="Spinner__container"
                    role="status"
                    css={{
                        color: theme.colors.text.default,
                        textAlign: "center",
                        display: "inline-block",
                        margin: 'auto'
                    }}
                >
                    <div
                        className="Spinner__spinner"
                        css={[
                            css`
            display: inline-block;
            vertical-align: text-bottom;
            border: 0.15em solid currentColor;
            border-right-color: transparent;
            border-radius: 50%;
            animation: ${spin} 0.75s linear infinite;
          `,
                            sizeStyles[size]
                        ]}
                    />
                    {label ? (
                        <Text
                            className="Spinner__label"
                            wrap={false}
                            css={{ display: "block", marginTop: theme.spaces.sm }}
                            variant="subtitle"
                        >
                            {label}
                        </Text>
                    ) : (
                        <VisuallyHidden.Root>Loading</VisuallyHidden.Root>
                    )}
                </div>
            </div>
        </div>
    );
};

